package com.michael.demos.base.design.singleton;

/**
 * 类功能描述:
 * <pre>
 *   单例模式
 * </pre>
 *
 * @author Michael
 * @version 1.0
 * @date 2020/8/17 11:07
 */
public class SingletonDemo {
    public static void main(String[] args) {
        Singleton8.INSTANCE.doSomething();
    }
}

/**
 * 双重检查模式
 * <pre>
 * 	推荐理由：
 * 		1. 延迟初始化。和懒汉模式一致，只有在初次调用静态方法 getSingleton，才会初始化 signleton 实例。
 * 		2. 性能优化。同步会造成性能下降，在同步前通过判读 singleton 是否初始化，减少不必要的同步开销。
 * 		3. 线程安全。同步创建Singleton对象，同时注意到静态变量 singleton 使用 volatile 修饰。
 * </pre>
 */
class Singleton {

    /** 1:volatile修饰 */
    private volatile static Singleton singleton;

    public static Singleton getSingleton() {
        //2:减少不要同步，优化性能
        if (singleton == null) {
            // 3：同步，线程安全
            synchronized (Singleton.class) {
                if (singleton == null) {
                    //4：创建singleton 对象
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }

    private Singleton() {}
}

/**
 * 静态内部类模式
 * <pre>
 * 	推荐理由：
 * 		1. 实现代码简洁。和双重检查单例对比，静态内部类单例实现代码真的是太简洁，又清晰明了。
 * 		2. 延迟初始化。调用getSingleton才初始化Singleton对象。
 * 		3. 线程安全。JVM在执行类的初始化阶段，会获得一个可以同步多个线程对同一个类的初始化的锁。
 * </pre>
 */
class Singleton2 {

    private Singleton2() {}

    public static Singleton2 getSingleton() {
        return Inner.instance;
    }

    private static class Inner {
        private static final Singleton2 instance = new Singleton2();
    }
}

/**
 * 懒汉模式(多线程不安全)
 */
class Singleton3 {
    private static Singleton3 instance;

    private Singleton3() {}

    public static Singleton3 getInstance() {
        if (instance == null) {
            instance = new Singleton3();
        }
        return instance;
    }
}

/**
 * 饿汉单例模式(多线程安全) —— 如果不使用会造成内存的浪费
 */
class Singleton4 {
    private static Singleton4 instance = new Singleton4();

    private Singleton4() {}

    public static Singleton4 getInstance() {
        return instance;
    }
}

/**
 * 枚举单例模式(多线程安全)
 */
class Singleton5 {

    private Singleton5() {}

    /**
     * 枚举类型是线程安全的，并且只会装载一次
     */
    private enum SingletonEnum {
        INSTANCE;

        private final Singleton5 instance;

        SingletonEnum() {
            instance = new Singleton5();
        }

        private Singleton5 getInstance() {
            return instance;
        }
    }

    public static Singleton5 getInstance() {

        return SingletonEnum.INSTANCE.getInstance();
    }
}

// 定义单例模式中需要完成的代码逻辑
interface MySingleton {
    void doSomething();
}

enum Singleton7 implements MySingleton {
    INSTANCE {
        @Override
        public void doSomething() {
            // 业务处理
        }
    };

    public static Singleton7 getInstance() {
        return Singleton7.INSTANCE;
    }
}

enum Singleton8 {
    INSTANCE;

    public void doSomething() {
        System.out.println("枚举单例模式");
    }
}

